package de.ghost23.common.statemachine {

	import de.ghost23.common.process.ACommand;
	import de.ghost23.common.process.ProcessEvent;
	import flash.events.EventDispatcher;
	import flash.utils.Dictionary;
	import flash.utils.describeType;
	import flash.utils.getQualifiedClassName;

	/**
	 * This state machine combines the use of commands with the management of a state network
	 * and the ability to navigate that network, if needed.
	 *
	 * <p>You use the state machine solely by extending StateMachine and defining the state
	 * network in the constructor. See the example for details. The state machine generally
	 * consists of states, commands and inputs. Currently, the state machine supports defining
	 * input commands, which get called, when its assigned state is entered.</p>
	 *
	 * <p>An input into the state machine is something, that can invoke a state change
	 * (it is like a transition with a transition condition in 'finite state machine'-terminology).
	 * Effectively it is a method call: <code>setInput(eventType:String)</code>, where
	 * eventType is an input type.</p>
	 *
	 * <p>When using the state machine, do not forget to call init(). Here is a usage example of
	 * a state machine. For information on how to create an individual state machine, see the examples
	 * at the bottom.</p>
	 <listing version="3.0">package {

	import de.ghost23.common.statemachine.StateMachineEvent;

	import flash.display.Sprite;
	import xmlStateMachine.XMLStateMachine;

	public class StateMachineTest extends Sprite {

		public function StateMachineTest() {

			var mySM:XMLStateMachine = new XMLStateMachine();
			mySM.addEventListener(StateMachineEvent.NEW_STATE, onNewState);
			mySM.addEventListener(StateMachineEvent.AIMED_STATE_REACHED, onAimedStateReached);
			mySM.init(); // Important !

			// We're interested for the state XML_PARSED
			mySM.aimForState(XMLStates.XML_PARSED);

			// We set off by injecting a new file to be parsed
			mySM.injectNewFileUrl("sample.xml"); // See examples at the bottom for details
		}

		private function onAimedStateReached(event:StateMachineEvent):void {
			trace("State XMLStates.XML_PARSED is reached!");
		}

		private function onNewState(event:StateMachineEvent):void {
			trace("New state reached -> " + event.currentState.identifier);
		}
	}
}</listing>
	 * 
	 * @example To explain its functionality further, let's look at an example first. In this example, we
	 * build a XML Loader/Parser by using our state machine. Please note, that in reality, this
	 * would probably not make sense, since it means quite a lot of code for so little purpose,
	 * but for demonstrating the state machine, it a quite a good example, because it holds quite
	 * a few topics: asynchronous tasks, passing data from one command to another and the possibility
	 * for a command to decide, which happens next.
	 * 
	 * <p>In order to build a state machine, it is recommended to create a class, that extends StateMachine:</p>
	 * 
	<listing version="3.0">package xmlStateMachine {
	import de.ghost23.common.statemachine.State;
	import de.ghost23.common.statemachine.StateMachine;

	import xmlStateMachine.commands.ParseXML;
	import xmlStateMachine.commands.RequestFile;
	import xmlStateMachine.commands.Reset;
	import xmlStateMachine.commands.UnloadFile;

	public class XMLStateMachine extends StateMachine {

		// Possible incoming events to change state
		public static const FILE_LOAD_REQUESTED:String      = "onFileLoadRequested";
		public static const FILE_LOAD_COMPLETE:String       = "onFileLoadComplete";
		public static const FILE_LOAD_FAILED:String         = "onFileLoadFailed";
		public static const FILE_UNLOAD_REQUESTED:String    = "onFileUnloadRequested";
		public static const XML_PARSING_STARTED:String      = "onXMLParsingStarted";
		public static const XML_PARSING_COMPLETE:String     = "onXMLParsingComplete";
		public static const XML_PARSING_FAILED:String       = "onXMLParsingFailed";
		public static const MACHINE_RESET:String            = "onMachineReset";

		// Definition of the state machine
		public function XMLStateMachine() {

			super(XMLStates.EMPTY_IDLE);

			states = XMLStates;

			XMLStates.EMPTY_IDLE.inputCommand = Reset;
			XMLStates.EMPTY_IDLE.stateAfterEvent[XMLStates.FILE_REQUESTING] = FILE_LOAD_REQUESTED;

			XMLStates.FILE_REQUESTING.inputCommand = RequestFile;
			XMLStates.FILE_REQUESTING.stateAfterEvent[XMLStates.FILE_LOADED] = FILE_LOAD_COMPLETE;
			XMLStates.FILE_REQUESTING.stateAfterEvent[XMLStates.FILE_LOADERROR] = FILE_LOAD_FAILED;

			XMLStates.FILE_LOADED.transient = true;
			XMLStates.FILE_LOADED.stateAfterEvent[XMLStates.XML_PARSING] = XML_PARSING_STARTED;

			XMLStates.FILE_LOADERROR.transient = true;
			XMLStates.FILE_LOADERROR.stateAfterEvent[XMLStates.EMPTY_IDLE] = MACHINE_RESET;

			XMLStates.XML_PARSING.inputCommand = ParseXML;
			XMLStates.XML_PARSING.stateAfterEvent[XMLStates.XML_PARSED] = XML_PARSING_COMPLETE;
			XMLStates.XML_PARSING.stateAfterEvent[XMLStates.XML_REJECTED] = XML_PARSING_FAILED;

			XMLStates.XML_PARSED.transient = true;
			XMLStates.XML_PARSED.stateAfterEvent[XMLStates.FILE_UNLOADING] = FILE_UNLOAD_REQUESTED;

			XMLStates.XML_REJECTED.transient = true;
			XMLStates.XML_REJECTED.stateAfterEvent[XMLStates.FILE_UNLOADING] = FILE_UNLOAD_REQUESTED;

			XMLStates.FILE_UNLOADING.inputCommand = UnloadFile;
			XMLStates.FILE_UNLOADING.stateAfterEvent[XMLStates.EMPTY_IDLE] = MACHINE_RESET;
		}
	}
}</listing>
	 * <p>You see two things here: First of all, a bunch of so called "incoming event" strings have been
	 * defined. These "events" (which are not real events, just string identifiers) define the possible
	 * signals, that can be called onto the state machine, to go from one state to another. If you
	 * visualize a state machine, you can think of these events to be the vectors from one state to another.</p>
	 * 
	 * <p>Secondly, you see some lines of code in the constructor. They actually define the state machine,
	 * in this case the XML Loader/Parser. I hope, that by simply reading the lines, you already get an idea,
	 * of what happens there. Let's take the first definition, for example:</p>
	<listing version="3.0">XMLStates.EMPTY_IDLE.inputCommand = Reset;
XMLStates.EMPTY_IDLE.stateAfterEvent[XMLStates.FILE_REQUESTING] = FILE_LOAD_REQUESTED;</listing>
	 * <p>There seems to be a class XMLStates, which has static properties. We visit that class later. For now,
	 * you only have to know, that this class holds a bunch of static properties, which are states, of type
	 * de.ghost23.common.statemachine.State. So, in the example above, for the state EMPTY_IDLE, we define
	 * an input command. We give it a class reference, Reset. An input command is an ACommand
	 * (de.ghost23.common.process.ACommand). It will be executed, once the state is entered. This input command
	 * is optional, you don't have to specify an input command, if nothing special should happen, once you
	 * enter a state.</p>
	 * 
	 * <p>Next, you see the line with the stateAfterEvent property. This is a Dictionary. Here you define, which
	 * state should follow the EMPTY_IDLE state, when a particular event comes in, in this case FILE_LOAD_REQUESTED.
	 * So you can read this line as: If the state machine is in the state EMPTY_IDLE, and the event FILE_LOAD_REQUESTED
	 * comes in, move to the state FILE_REQUESTING.</p>
	 * 
	 * <p>You will notice, that the other lines of code in the constructor mostly do similar things. Sometimes,
	 * they define no input command, sometimes they define not only one following state, but multiple. And sometimes
	 * a state is defined to be 'transient'. That means, that the state machine will try to move the next state,
	 * right after this one has been entered. So a transient state is normally very short-lived and not intended
	 * to stay for long. For example, the state XML_REJECTED is transient. Why? Because, if an xml file has been
	 * rejected because of bad syntax or content, there is no use of staying in that state for long. Instead, it makes
	 * sense to go back to the EMPTY_IDLE state again, so that a new xml file can be loaded. The same is true for
	 * the case, that xml file has been parsed successfully. It makes no sense to stay in that state for long, instead
	 * it is better to go back to idle to be ready to take another xml file, if needed.</p>
	 * 
	 * <p>Now let's look at that XMLStates class. It is simply used as a container object for storing the possible
	 * states for this state machine and as an enumeration object:</p>
	<listing version="3.0">package xmlStateMachine {
	import de.ghost23.common.statemachine.State;

	public class XMLStates {

		// The states
		public static const EMPTY_IDLE:State        = new State("EMPTY_IDLE");
		public static const FILE_REQUESTING:State   = new State("FILE_REQUESTING");
		public static const FILE_LOADED:State       = new State("FILE_LOADED");
		public static const FILE_LOADERROR:State    = new State("FILE_LOADERROR");
		public static const XML_PARSING:State       = new State("XML_PARSING");
		public static const XML_PARSED:State        = new State("XML_PARSED");
		public static const XML_REJECTED:State      = new State("XML_REJECTED");
		public static const FILE_UNLOADING:State    = new State("FILE_UNLOADING");
	}
}</listing>
	 * <p>You could also use a simple Object for doing it, but using a class and static properties
	 * has the advantage of having code completion and compile-time checking.</p>
	 * 
	 * <p>You might ask yourself, how do we actually tell the state machine to load a particular file?
	 * We have to add some methods to our individual state machine to that, this isn't something,
	 * that StateMachine dictates. So let's look at XMLStateMachine again, this time with some
	 * usefull methods:</p>
	<listing version="3.0">package xmlStateMachine {
	import de.ghost23.common.statemachine.State;
	import de.ghost23.common.statemachine.StateMachine;

	import flash.net.URLLoader;

	import xmlStateMachine.commands.ParseXML;
	import xmlStateMachine.commands.RequestFile;
	import xmlStateMachine.commands.Reset;
	import xmlStateMachine.commands.UnloadFile;

	public class XMLStateMachine extends StateMachine {

		// Possible incoming events to change state
		public static const FILE_LOAD_REQUESTED:String      = "onFileLoadRequested";
		public static const FILE_LOAD_COMPLETE:String       = "onFileLoadComplete";
		public static const FILE_LOAD_FAILED:String         = "onFileLoadFailed";
		public static const FILE_UNLOAD_REQUESTED:String    = "onFileUnloadRequested";
		public static const XML_PARSING_STARTED:String      = "onXMLParsingStarted";
		public static const XML_PARSING_COMPLETE:String     = "onXMLParsingComplete";
		public static const XML_PARSING_FAILED:String       = "onXMLParsingFailed";
		public static const MACHINE_RESET:String            = "onMachineReset";

		// Possible data field names
		public static const PARSED_OBJECT:String            = "parsedObject";
		public static const FILE_URL:String                 = "fileURL";
		public static const FILE_RAW_XML:String             = "fileXML";

		// Data fields of this particular state machine

		public function get fileURL():String {
			return _data[FILE_URL];
		}

	 	public function get rawXMLFile():URLLoader {
			return _data[FILE_RAW_XML];
		}

		public function get parsedXMLObject():Object {
			return _data[PARSED_OBJECT];
		}

		public function setNewFile(url:String):void {
			_data[FILE_URL] = url;
			try {
				setInput(FILE_LOAD_REQUESTED);
			}catch(e:Error) {
				trace("invoking event FILE_LOAD_REQUESTED not " +
						"possible in current state: " + currentState.identifier);
			}
		}

		// Definition of the state machine
		public function XMLStateMachine() {

			super(XMLStates.EMPTY_IDLE);

			states = XMLStates;

			XMLStates.EMPTY_IDLE.inputCommand = Reset;
			XMLStates.EMPTY_IDLE.stateAfterEvent[XMLStates.FILE_REQUESTING] = FILE_LOAD_REQUESTED;

			XMLStates.FILE_REQUESTING.inputCommand = RequestFile;
			XMLStates.FILE_REQUESTING.stateAfterEvent[XMLStates.FILE_LOADED] = FILE_LOAD_COMPLETE;
			XMLStates.FILE_REQUESTING.stateAfterEvent[XMLStates.FILE_LOADERROR] = FILE_LOAD_FAILED;

			XMLStates.FILE_LOADED.transient = true;
			XMLStates.FILE_LOADED.stateAfterEvent[XMLStates.XML_PARSING] = XML_PARSING_STARTED;

			XMLStates.FILE_LOADERROR.transient = true;
			XMLStates.FILE_LOADERROR.stateAfterEvent[XMLStates.EMPTY_IDLE] = MACHINE_RESET;

			XMLStates.XML_PARSING.inputCommand = ParseXML;
			XMLStates.XML_PARSING.stateAfterEvent[XMLStates.XML_PARSED] = XML_PARSING_COMPLETE;
			XMLStates.XML_PARSING.stateAfterEvent[XMLStates.XML_REJECTED] = XML_PARSING_FAILED;

			XMLStates.XML_PARSED.transient = true;
			XMLStates.XML_PARSED.stateAfterEvent[XMLStates.FILE_UNLOADING] = FILE_UNLOAD_REQUESTED;

			XMLStates.XML_REJECTED.transient = true;
			XMLStates.XML_REJECTED.stateAfterEvent[XMLStates.FILE_UNLOADING] = FILE_UNLOAD_REQUESTED;

			XMLStates.FILE_UNLOADING.inputCommand = UnloadFile;
			XMLStates.FILE_UNLOADING.stateAfterEvent[XMLStates.EMPTY_IDLE] = MACHINE_RESET;
		}
	}
}</listing>
	 * <p>You now see some methods been added to the class, like <code>setNewFile(url:String)</code>. Most
	 * if these methods make use of the protected property _data, which is also accessible publicly via
	 * 'data'. _data is a Dictionary and it is passed to every ACommand to share data. In the examples,
	 * you see lines like: <code>_data[RequestFile.FILE_URL] = url;</code>. It is good practice to use
	 * constants from the used commands to specify, how to identify a particular data field. In the little
	 * example here, the command RequuestFile specifies a data field name FILE_URL. So the XMLStateMachine
	 * uses that name to set the file url.</p>
	 * 
	 * <p>Why is it done this way? The idea is, that for the command to
	 * be mostly independent of anything else, it defines the fields, it needs. The state machine, that
	 * brings everything together, has to know these and populate the fields accordingly. So the dependency
	 * graph is top-down, which is normally a good approach, because it makes the commands be reusable. Of course,
	 * you could also decide for doing it differently, the state machine itself doesn't force a particular
	 * approach. To have the complete picture, let's look at the RequestFile command:</p>
	<listing version="3.0">package xmlStateMachine.commands {

	import de.ghost23.common.process.ACommand;

	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	import xmlStateMachine.XMLStateMachine;

	public class RequestFile extends ACommand {

		private var xmlLoader:URLLoader;
		private var data:Dictionary;

		public function RequestFile() {
			super();
		}

		override public function execute(paramContainer:Dictionary):void {

			trace("command RequestFile is running with file: " + paramContainer[XMLStateMachine.FILE_URL]);
			data = paramContainer;

			if(data[XMLStateMachine.FILE_URL] == null) setResult(FAILURE);
			else {

				xmlLoader = new URLLoader();
				xmlLoader.addEventListener(Event.COMPLETE, onLoadComplete);
				xmlLoader.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
				xmlLoader.load(new URLRequest(data[XMLStateMachine.FILE_URL]));
			}
		}

		private function onLoadError(event:IOErrorEvent):void {

			xmlLoader.removeEventListener(Event.COMPLETE, onLoadComplete);
			xmlLoader = null;
			data = null;
			setResult(XMLStateMachine.FILE_LOAD_FAILED);
		}

		private function onLoadComplete(event:Event):void {

			data[XMLStateMachine.FILE_RAW_XML] = xmlLoader;
			xmlLoader.removeEventListener(Event.COMPLETE, onLoadComplete);
			xmlLoader = null;
			data = null;
			setResult(XMLStateMachine.FILE_LOAD_COMPLETE);
		}
	}
}</listing>
	 * <p>For some detailed explanation of ACommand, see its documentation. Here, please 
	 * concentrate on the execute method, which has the parameter 'data', which is the reference
	 * to the _data field of our state machine.</p>
	 * @author Sven Busse
	 * @version 1.0
	 */
	public class StateMachine extends EventDispatcher {

		/**
		 * An enumeration object, that holds all the states, this state machine knows of.
		 * This can either be a simple object, or (recommended) a class with static properties.
		 * Using the latter gives you the advantage of having code completion in your editor.
		 * Such a class would look like this:
		 * @example
		 <listing version="3.0">package xmlStateMachine {
	import de.ghost23.common.statemachine.State;

	public class XMLStates {

		// The states
		public static const EMPTY_IDLE:State        = new State("EMPTY_IDLE");
		public static const FILE_REQUESTING:State   = new State("FILE_REQUESTING");
		public static const FILE_LOADED:State       = new State("FILE_LOADED");
		public static const FILE_LOADERROR:State    = new State("FILE_LOADERROR");
		public static const XML_PARSING:State       = new State("XML_PARSING");
		public static const XML_PARSED:State        = new State("XML_PARSED");
		public static const XML_REJECTED:State      = new State("XML_REJECTED");
		public static const FILE_UNLOADING:State    = new State("FILE_UNLOADING");
	}
}</listing>
		 */
		protected var states:Object;

		/**
		 * The current input command. This variable is null, unless a command is indeed running currently.
		 */
		protected var currentInputCommand:ACommand;

		/**
		 * The state, that has been set by <code>aimForTarget(state:State)</code>. If no target was
		 * set, or the target has been reached, this is null.
		 */
		protected var targetState:State;
		
		private var _data:Dictionary;
		private var targetPath:Vector.<State>;
		private var _currentState:State;
		private var initialized:Boolean = false;

		/**
		 * The current state, the state machine is in. As long the state machine has not been initialized
		 * with <code>init()</code>, this is null.
		 */
		public function get currentState():State {
			return _currentState;
		}

		/**
		 * A general purpose data container, that is shared among the commands, which are part of
		 * this state machine. This data Dictionary is passed as a reference to each executed command
		 * via its execute method.
		 */
		public function get data():Dictionary {
			return _data;
		}

		/**
		 * Constructs a new state machine.
		 * <p>You will never instantiate StateMachine directly, instead you will subclass ist
		 * and call the super constructor there. See the examples at the bottom.</p>
		 * @param startState The state, in which the state machine will begin after <code>init()</code> has
		 * been called.
		 */
		public function StateMachine(startState:State) {

			_currentState = startState;
			_data = new Dictionary();
		}

		/**
		 * Initializes the state machine. Before init() is called, the state machine has no defined state.
		 * The reason for init() is, that you are able to add yourself as a listener to the state machine,
		 * before the state machine actually begins.
		 */
		public function init():void {

			initialized = true;
			dispatchEvent(
				new StateMachineEvent(
					StateMachineEvent.NEW_STATE,
					null,
					_currentState,
					null
				)
			);
			executeCurrentInputCommand();
		}

		/**
		 * Sets a target state, that the state machine will try to reach withing the bounds of the
		 * defined state network.
		 * <p>One of the features of StateMachine is, that it is navigable. With aimForState(targetState:State)
		 * you can set a state, that you want to reach and the state machine will navigate towards that
		 * state, if there are forks in the path, which allow for the state machine to make autonomous decisions.
		 * For example, consider this little state machine definition:</p>
		 <listing version="3.0">SomeStates.FIRST_STATE.transient = true;
SomeStates.FIRST_STATE.stateAfterEvent[SomeStates.SECOND_STATE] = THIS_HAPPENED;
SomeStates.FIRST_STATE.stateAfterEvent[SomeStates.THIRD_STATE] = THAT_HAPPENED;
</listing>
		 * FIRST_STATE is transient, means, the state machine will directly try to move to the next state, if FIRST_STATE
		 * has been entered. The question is, which state should the state machine go to? Let's assume, you have
		 * called <code>aimForState(SomeStates.THIRD_STATE);</code> before. Then now the state machine will look for the
		 * shortest path from FIRST_STATE to THIRD_STATE (which in this case is easy) and will automatically invoke
		 * input calls (setInput()), that lead to the state aimed for. It does this only for transient states, of course,
		 * because only then it gets the power over the control flow.
		 * @param targetState The state, you are aiming to reach.
		 * @see de.ghost23.common.statemachine.StateMachineEvent#AIMED_STATE_REACHED
		 */
		public function aimForState(targetState:State):void {

			if(!initialized) throw new Error("StateMachine has not yet been initialized. Use init() first!");
			this.targetState = targetState;
			targetPath = createTargetStatePath(_currentState, targetState);
		}

		/**
		 * Sets a new input signal (which is similar to a transformation route in traditional finite state machine terminology).
		 * @param eventType The input type. Usually you will define the possible input types as constants in your
		 * individual state machine. See examples at the bottom.
		 */
		public function setInput(eventType:String):void {

			if(!initialized) throw new Error("StateMachine has not yet been initialized. Use init() first!");
			var stateForEvent:State;
			for(var elmt:* in _currentState.stateAfterEvent) {
				if(eventType == _currentState.stateAfterEvent[elmt]) {
					stateForEvent = elmt;
					break;
				}
			}
			if(stateForEvent == null) {
				throw new Error(
						"Incoming Event '" + eventType + "' is not an allowed event for the current state '"
								+ _currentState.identifier + "'");
			}

			setNewState(stateForEvent);
		}

		private function executeCurrentInputCommand():void {

			if(_currentState.inputCommand != null) {
				if(currentInputCommand != null) clearCurrentInputCommand();
				currentInputCommand = new _currentState.inputCommand();
				currentInputCommand.addEventListener(ProcessEvent.COMPLETED, onInputCommandComplete);
				currentInputCommand.addEventListener(ProcessEvent.FAILED, onInputCommandFailed);
				currentInputCommand.execute(_data);
			}else {
				onInputCommandComplete(new ProcessEvent(ProcessEvent.COMPLETED), true);
			}
		}

		private function onInputCommandFailed(event:ProcessEvent):void {

			trace("INPUT COMMAND FAILED!!! " + getQualifiedClassName(currentInputCommand));
			trace("STATEMACHINE IS IN AN UNDEFINED STATE!!!");
			clearCurrentInputCommand();
		}

		private function onInputCommandComplete(event:ProcessEvent, fake:Boolean = false):void {

			if(!fake) clearCurrentInputCommand();

			if(_currentState.transient) {
				if(targetPath != null && targetPath.length > 1) setInput(_currentState.stateAfterEvent[targetPath[1]]);
				else {
					var stateAfterEventList:Vector.<String> = new Vector.<String>();
					for(var elmt:* in _currentState.stateAfterEvent) {
						stateAfterEventList.push(_currentState.stateAfterEvent[elmt]);
					}
					if(stateAfterEventList.length == 1) setInput(stateAfterEventList[0]);
				}
			}else if(event.resultCode != null) {
				setInput(event.resultCode);
			}
		}

		private function clearCurrentInputCommand():void {

			currentInputCommand.removeEventListener(ProcessEvent.COMPLETED, onInputCommandComplete);
			currentInputCommand.removeEventListener(ProcessEvent.FAILED, onInputCommandFailed);
			currentInputCommand = null;
		}

		private function setNewState(newState:State):void {

			var previousState:State = _currentState;
			_currentState = newState;

			if(targetPath != null && _currentState == targetState) {

				targetPath = null;
				targetState = null;
				dispatchEvent(
					new StateMachineEvent(
						StateMachineEvent.AIMED_STATE_REACHED,
						previousState,
						_currentState,
						_currentState
					)
				);
			}else if(targetPath != null && targetPath.length > 1) {

				targetPath.shift();
				if(_currentState != targetPath[0]) {
					targetPath = createTargetStatePath(_currentState, targetState);
				}
			}

			dispatchEvent(
				new StateMachineEvent(
					StateMachineEvent.NEW_STATE,
					previousState,
					_currentState,
					targetState
				)
			);

			executeCurrentInputCommand();
		}

		/**
		 * Searches a path from the current state to a specified target state,
		 * using the depth-first algorithm.
		 * @param startState
		 */
		private function createTargetStatePath(startState:State, targetState:State):Vector.<State> {

			var pathToTarget:Vector.<State> = new Vector.<State>;

			var currentState:State = targetState;
			var predecessors:Dictionary = dijkstra(startState);
			while(predecessors[currentState] != null) {  // Der Vorg�nger des Startknotens ist null
				pathToTarget.unshift(predecessors[currentState]);
				currentState = predecessors[currentState];
			}
			return pathToTarget;
		}

		private function buildEnumObjectFromClass(sourceObject:*):Object {

			var result:Object = new Object();
			// determine if o is a class instance or a plain object
			var classInfo:XML = describeType( sourceObject );

			// Loop over all of the variables and accessors in the class and
			// serialize them along with their values.
			for each (var v:XML in classInfo..*.(
					name() == "variable" || name() == "constant"
					)) {

				// If [Transient] metadata exists, then we should skip
				if (v.@name == "prototype" || (v.metadata && v.metadata.( @name == "Transient" ).length() > 0)) {
					continue;
				}

				result[v.@name] = sourceObject[v.@name];
			}

			return result;
		}

		// --------------- Dijkstra implementation for finding the shortest path from one state to another.

		private function dijkstra(startState:State):Dictionary {

			var distances:Dictionary = new Dictionary();
			var predecessors:Dictionary = new Dictionary();
			var stateList:Vector.<State> = new Vector.<State>();
			var statesEnum:Object = buildEnumObjectFromClass(states);

			for each(var item:Object in statesEnum) {
				distances[item] = Number.POSITIVE_INFINITY;
				predecessors[item] = null;
				stateList.push(item);
			}
			distances[startState] = 0;

			var stateWithSmallestDistance:State;
			var followersOfState:Dictionary;

			/*	a negative number, if x should appear before y in the sorted sequence
				0, if x equals y
				a positive number, if x should appear after y in the sorted sequence
			*/
			var sortForSmallestDistance:Function = function(x:State, y:State):Number {
				return distances[x] - distances[y];
			};

			while(stateList.length > 0) { // Der eigentliche Algorithmus

				stateWithSmallestDistance = Vector.<State>(stateList.sort(sortForSmallestDistance))[0];

				// An alternative within dijkstra. Since we have found our target already, we can abort the rest.
				if(stateWithSmallestDistance === null) return predecessors;

				stateList.splice(stateList.indexOf(stateWithSmallestDistance),1);

				followersOfState = stateWithSmallestDistance.stateAfterEvent;

				for(var elmt:* in followersOfState) {
					if(stateList.indexOf(elmt) > -1){
						updateDistance(stateWithSmallestDistance, elmt, distances, predecessors);
					}
				}
			}
			return predecessors;
		}

		private function updateDistance(stateWithSmallestDistance:State, neighbour:State, distance:Dictionary, predecessor:Dictionary):void {

			// 1 is the weight of the line between stateWithSmallestDistance and neighbour
			// We do not use weights, that's why we give 1 here in general.
			var alternative:Number = distance[stateWithSmallestDistance] + 1;

			if(alternative < distance[neighbour]) {
				distance[neighbour] = alternative;
				predecessor[neighbour] = stateWithSmallestDistance;
			}
		}
	}
}